1 Tekrarlanabilir Analiz ve Rapor


1.2 Replication Crisis Excel Version


2 RStudio ile proje oluştur


3 R Notebook

3.1 R Notebook dökümanı oluşturma


3.2 R Notebook’tan html, pdf ve word oluşturma


3.3 RNotebook vs RMarkdown

https://youtu.be/zNzZ1PfUDNk


4 R Markdown

4.1 Hem kendi kodları hem de html kodları yazılabilir

https://rmarkdown.rstudio.com

What is R Markdown? from RStudio, Inc. on Vimeo.


4.2 R Markdown: The Definitive Guide

https://bookdown.org/yihui/rmarkdown/


4.3 R Markdown syntax

https://gist.github.com/MinhasKamal/7fdebb7c424d23149140


4.4 Remedy Package


4.4.1 Remedy


4.6 Render Markdown via code

inside R

markdown::markdownToHTML('markdown_example.md', 
'markdown_example.html')

command line

R -e "markdown::markdownToHTML('markdown_example.md',
'markdown_example.html')"

4.7 pandoc Rstudio integration

command line

export PATH=$PATH:/Applications/RStudio.app/Contents/MacOS/pandoc
R -e "rmarkdown::render('markdown_example.md')"

5 RMarkdown chunk içinde R kodlarını çalıştırma

{r, results='asis'}
 iris %>%
  tibble::as_tibble() %>%
  details::details(summary = 'tibble')

6 Metin arasında R kodlarını çalıştırma


7 Chunk Options

7.1 Global Options

{r global_options, include=FALSE}
knitr::opts_chunk$set(fig.width = 12,
                      fig.height = 8,
                      fig.path = 'Figs/',
                      echo = FALSE,
                      warning = FALSE,
                      message = FALSE,
                      error = FALSE,
                      eval = TRUE,
                      tidy = TRUE,
                      comment = NA)

7.2 Other Code Languages


8 R Markdown kod örneği

{r}
data("cancer")
cancer
foreign::write.foreign(df = cancer,
                        datafile = "data/cancer.sav",
                        codefile = "data/cancer.spo",
                        package = "SPSS"
                        )

9 R Markdown Paket Çağırma 📦

{r}
suppressPackageStartupMessages(library("tidyverse"))
suppressPackageStartupMessages(library("survival"))

9.1 Sık kullandığım paketler 📦

{tidyverse} {tidylog}

{lubridate} {janitor}

{readxl} {foreign}

{summarytools} {ggstatsplot} {tangram} {finalfit} {psycho} {jmv}

{survival} {survminer}

{report} {kableExtra}


10 R Markdown Veri Yükleme SPSS


11 R Markdown Veri Yükleme Excel


12 Veri Düzenleme

{r, eval=FALSE, include=FALSE, eval=FALSE, include=FALSE}
mydata <- janitor::clean_names(mydata)
cat(names(mydata), sep = ",\n")
{r}
glimpse(mydata)
{r, eval=FALSE, include=FALSE, eval=FALSE, include=FALSE}
## Recoding mydata$cinsiyet into mydata$Cinsiyet
mydata$Cinsiyet <- recode(mydata$cinsiyet,
               "K" = "Kadin",
               "E" = "Erkek")
mydata$Cinsiyet <- factor(mydata$Cinsiyet)
{r recode TNM stage, eval=FALSE, include=FALSE}
mydata$Tstage <- stringr::str_match(mydata$patolojik_evre, paste('(.+)', "N", sep=''))[,2]

mydata$Nstage <- paste0("N",
    stringr::str_match(mydata$patolojik_evre, paste( "N", '(.+)', "M", sep=''))[,2]
    )

mydata$Mstage <- paste0("M", 
    stringr::str_match(mydata$patolojik_evre, paste("M", '(.+)', sep=''))[,2]
)
{r recode TNM2, eval=FALSE, include=FALSE}
mydata <- mydata %>% 
    mutate(
        T_stage = case_when(
            grepl(pattern = "T1", x = .$Tstage) == TRUE ~ "T1",
            grepl(pattern = "T2", x = .$Tstage) == TRUE ~ "T2",
            grepl(pattern = "T3", x = .$Tstage) == TRUE ~ "T3",
            grepl(pattern = "T4", x = .$Tstage) == TRUE ~ "T4",
            TRUE ~ "Tx"
        )
    ) %>% 
mutate(
        N_stage = case_when(
            grepl(pattern = "N0", x = .$Nstage) == TRUE ~ "N0",
            grepl(pattern = "N1", x = .$Nstage) == TRUE ~ "N1",
            grepl(pattern = "N2", x = .$Nstage) == TRUE ~ "N2",
            grepl(pattern = "N3", x = .$Nstage) == TRUE ~ "N3",
            TRUE ~ "Nx"
        )
    ) %>% 
mutate(
        M_stage = case_when(
            grepl(pattern = "M0", x = .$Mstage) == TRUE ~ "M0",
            grepl(pattern = "M1", x = .$Mstage) == TRUE ~ "M1",
            TRUE ~ "Mx"
        )
    )

{r, eval=FALSE, include=FALSE}
mydata <- mydata %>% 
    mutate(
TumorPDL1gr1 = case_when(
        t_pdl1 < 1 ~ "kucuk1",
        t_pdl1 >= 1 ~ "buyukesit1"
    )
    ) %>% 
mutate(
TumorPDL1gr5 = case_when(
        t_pdl1 < 5 ~ "kucuk5",
        t_pdl1 >= 5 ~ "buyukesit5"
    )
    )   %>% 
mutate(
inflPDL1gr1 = case_when(
        i_pdl1 < 1 ~ "kucuk1",
        i_pdl1 >= 1 ~ "buyukesit1"
    )
    ) %>% 
mutate(
inflPDL1gr5 = case_when(
        i_pdl1 < 5 ~ "kucuk5",
        i_pdl1 >= 5 ~ "buyukesit5"
    )
    )
{r, eval=FALSE, include=FALSE}
mydata$sontarih <- janitor::excel_numeric_to_date(as.numeric(mydata$olum_tarihi))
{r, eval=FALSE, include=FALSE}
mydata$Outcome <- "Dead"
mydata$Outcome[mydata$olum_tarihi == "yok"] <- "Alive"

13 R Markdown Tanımlayıcı İstatistikler

{r}
library(summarytools)
view(dfSummary(colon_s))

13.1 Table One

{r, results='asis'}
# cat(names(mydata), sep = " + \n")
library(arsenal)
tab1 <- tableby(~ Cinsiyet + 
Yas + 
TumorYerlesimi
                ,
                data = mydata)
summary(tab1)

13.3 Kategorik Veriler

{r ", names(mydataCategorical)[i], "}
mydataCategorical %>% 
  janitor::tabyl(", names(mydataCategorical)[i], ") %>%
  adorn_pct_formatting(rounding = 'half up', digits = 1) %>%
  knitr::kable()
{r crosstable", dependent_variable, "}
mydata %>%
    summary_factorlist(dependent = '", dependent_variable, "', 
                       explanatory = explanatory,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE) -> table

knitr::kable(table, row.names = FALSE, align = c('l', 'l', 'r', 'r', 'r'))

13.4 Kategorik Veriler için Grafikler

{r ggstatplot ", dependent_variable , " vs ", mydataCategorical_variable, ", layout='l-page'}
mydata %>% 
    ggstatsplot::ggbarstats(data = ., main = ", mydataCategorical_variable, ", condition = ", dependent_variable, ")

13.5 Continious Variables

{r ", names(mydataContinious)[i], "}
mydataContinious %>% 
jmv::descriptives(
    data = .,
    vars = ", names(mydataContinious)[i], ",
    hist = TRUE,
    dens = TRUE,
    box = TRUE,
    violin = TRUE,
    dot = TRUE,
    mode = TRUE,
    sd = TRUE,
    variance = TRUE,
    skew = TRUE,
    kurt = TRUE,
    quart = TRUE)

14 R Markdown Recode

recode


15 R Markdown örneği Çapraz Tablolar

library(finalfit)

{r crosstable", dependent_variable, ", message=FALSE, warning=FALSE}
mydata %>%
    summary_factorlist(dependent = '", dependent_variable, "', 
                       explanatory = explanatory,
                       column = TRUE,
                       total_col = TRUE,
                       p = TRUE,
                       add_dependent_label = TRUE,
                       na_include=FALSE
                       # catTest = catTestfisher
                       ) -> table

knitr::kable(table, row.names = FALSE, align = c('l', 'l', 'r', 'r', 'r'))

16 R Markdown örneği Sağkalım

16.1 Kaplan-Meier

{r Kaplan-Meier}
mydata %>%
  finalfit::surv_plot(dependent,
                      explanatory,
                      xlab='Time (months)',
                      pval=TRUE,
                      legend = 'none',
                      break.time.by = 12,
                      xlim = c(0,60),
                      legend.labs = c('a','b')
)

16.2 Sağkalım Tabloları

{r}
km_fit <- survfit(dependent ~ explanatory,
                  data = mydata)
km_fit
{r, eval=FALSE, include=FALSE}
library(survival)
km <- with(mydata, Surv(OverallTime, Outcome2))
# head(km,80)
# plot(km)
{r 1-3-5-yr}
summary(km_fit, times = c(12,36,60))

17 Pairwise comparison

{r eval=FALSE, include=FALSE}
survminer::pairwise_survdiff(formula = Surv(time, Outcome) ~ ShellAnteriorOnly, 
                             data = mydata,
                             p.adjust.method = "BH")

18 Multivariate Analysis Survival

{r Multivariate Analysis, eval=FALSE, include=FALSE}
library(finalfit)
library(survival)
explanatoryMultivariate <- explanatoryKM
dependentMultivariate <- dependentKM

mydata %>%
  finalfit(dependentMultivariate, explanatoryMultivariate) -> tMultivariate

knitr::kable(tMultivariate, row.names=FALSE, align=c("l", "l", "r", "r", "r", "r"))
{r define survival time, eval=FALSE, include=FALSE}
mydata$int <- lubridate::interval(
  lubridate::ymd(mydata$CerrahiTarih),
  lubridate::ymd(mydata$SonTarih)
  )
mydata$OverallTime <- lubridate::time_length(mydata$int, "month")
mydata$OverallTime <- round(mydata$OverallTime, digits = 1)
{r, eval=FALSE, include=FALSE}
mydata$OverallTime <- mydata$genel_sagkalim
{r, eval=FALSE, include=FALSE}
## Recoding mydata$Outcome into mydata$Outcome2
mydata$Outcome2 <- recode(mydata$Outcome,
               "Alive" = "0",
               "Dead" = "1")
mydata$Outcome2 <- as.numeric(mydata$Outcome2)

20 {jmv} paket kodları

jamovi syntax mode


21 Güncellemeler olunca kodlar çalışacak mı?


21.1 Paket Kütüphaneleri

  • packrat / renv

https://environments.rstudio.com


21.2 Docker

  • docker

21.2.1 The Rocker Project

Docker Containers for the R Environment

docker run --rm -ti rocker/r-base

Or get started with an RStudio® instance:

docker run -e PASSWORD=yourpassword --rm -p 8787:8787 rocker/rstudio

and point your browser to localhost:8787 Log in with user/password rstudio/yourpassword


Managing containers


21.3 Yeni R sürümleri

  • RSwitch

https://rud.is/rswitch/

  • Using RSwitch

https://rud.is/rswitch/guide/

: scale 30%


22 Yedeklemeyi nasıl yapacağız

22.1 Projeyi düzgün organize edin

  • pdf
  • R
  • images
  • bib
{r load library, include=FALSE}
source(file = here::here("R", "loadLibrary.R"))

22.2 Save Final Data

{r}
saved data after analysis to `mydata.xlsx`.

save.image(file = here::here("data", "mydata_work_space.RData"))

readr::write_rds(x = mydata, path = here::here("data", "mydata_afteranalysis.rds"))

saveRDS(object = mydata, file = here::here("data", "mydata.rds"))

writexl::write_xlsx(mydata, here::here("data", "mydata.xlsx"))

paste0(rownames(file.info(here::here("data", "mydata.xlsx"))), " : ", file.info(here::here("data", "mydata.xlsx"))$ctime)

22.3 GitHub

{r github push}
CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )
system(command = gitCommand,
       intern = TRUE
)

22.4 GitHub Yedekleme

CommitMessage <- paste("updated on ", Sys.time(), sep = "")
wd <- getwd()
gitCommand <- paste("cd ", 
                    wd,
                    " \n git add . \n git commit --message '",
                    CommitMessage,
                    "' \n git push origin master \n",
                    sep = ""
                    )

system(command = gitCommand,
       intern = TRUE
)

23 Her dökümanın sonuna kullandığınız kütüphaneler için atıf yazdırabilirsiniz

{r library citation, echo=TRUE}
citation()

23.1 Libraries Used

citation()

23.2 Bu oturuma spesifik kullanılan paketler

report::cite_packages(session = sessionInfo())

23.3 Tek tek paket atıfları

{r library citations}
citation("tidyverse")
{r}
citation("readxl")
citation("janitor")
citation("report")
citation("finalfit")
citation("ggstatplot")

23.4 Jamovi ve R için atıf örneği

The jamovi project (2019). jamovi. (Version 0.9) [Computer Software]. Retrieved from https://www.jamovi.org. R Core Team (2018). R: A Language and envionment for statistical computing. [Computer software]. Retrieved from https://cran.r-project.org/. Fox, J., & Weisberg, S. (2018). car: Companion to Applied Regression. [R package]. Retrieved from https://cran.r-project.org/package=car.


24 Her dökümanın sonuna oturum detaylarınızı yazdırabilirsiniz

{r session info, echo=TRUE}
sessionInfo()

24.1 Session Info

sessionInfo()

25 Sonraki Konular

  • RStudio ile GitHub kullanımı

27 Geri Bildirim




  1. Bu bir derlemedir, mümkün mertebe alıntılara linklerle referans vermeye çalıştım.↩︎

LS0tCnRpdGxlOiBSLCBSU3R1ZGlvIHZlIFJNYXJrZG93biBpbGUgVGVrcmFybGFuYWJpbGlyIFJhcG9yXltCdSBiaXIgZGVybGVtZWRpciwgbcO8bWvDvG4gbWVydGViZSBhbMSxbnTEsWxhcmEgbGlua2xlcmxlIHJlZmVyYW5zIHZlcm1leWUgw6dhbMSxxZ90xLFtLl0KYXV0aG9yOiAiW1NlcmRhciBCYWxjxLEsIE1ELCBQYXRob2xvZ2lzdF0oaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvLykiCmluc3RpdHV0ZTogIltzZXJkYXJiYWxjaS5jb21dKGh0dHBzOi8vd3d3LnNlcmRhcmJhbGNpLmNvbSkiCmRhdGU6ICJgciBmb3JtYXQoU3lzLkRhdGUoKSlgIgpvdXRwdXQ6CiAgcmV2ZWFsanM6OnJldmVhbGpzX3ByZXNlbnRhdGlvbjoKICAgIGluY3JlbWVudGFsOiB0cnVlCiAgICB0aGVtZTogc2t5CiAgICBoaWdobGlnaHQ6IHB5Z21lbnRzCiAgICBjZW50ZXI6IGZhbHNlCiAgICBzbWFydDogdHJ1ZQogICAgdHJhbnNpdGlvbjogZmFkZQogICAgc2VsZl9jb250YWluZWQ6IHRydWUKICAgIGlnX3dpZHRoOiA3CiAgICBmaWdfaGVpZ2h0OiA2CiAgICBmaWdfY2FwdGlvbjogdHJ1ZQogICAgcmV2ZWFsX29wdGlvbnM6CiAgICAgIHNsaWRlTnVtYmVyOiB0cnVlCiAgICAgIHByZXZpZXdMaW5rczogdHJ1ZQogIHJtZHNob3dlcjo6c2hvd2VyX3ByZXNlbnRhdGlvbjoKICBodG1sX25vdGVib29rOgogICAgZmlnX2NhcHRpb246IHllcwogICAgaGlnaGxpZ2h0OiBrYXRlCiAgICBudW1iZXJfc2VjdGlvbnM6IHllcwogICAgdGhlbWU6IGZsYXRseQogICAgdG9jOiB5ZXMKICAgIHRvY19kZXB0aDogNQogICAgdG9jX2Zsb2F0OiB5ZXMKICB4YXJpbmdhbjo6bW9vbl9yZWFkZXI6CiAgICBsaWJfZGlyOiBsaWJzCiAgICBuYXR1cmU6CiAgICAgIGJlZm9yZUluaXQ6IFsibWFjcm9zLmpzIiwgImh0dHBzOi8vcGxhdGZvcm0udHdpdHRlci5jb20vd2lkZ2V0cy5qcyJdCiAgICAgIGhpZ2hsaWdodFN0eWxlOiBnaXRodWIKICAgICAgaGlnaGxpZ2h0TGluZXM6IHRydWUKICAgICAgY291bnRJbmNyZW1lbnRhbFNsaWRlczogZmFsc2UKICAgIHNlbGZfY29udGFpbmVkOiB0cnVlCiAgcHJldHR5ZG9jOjpodG1sX3ByZXR0eToKICAgIHRoZW1lOiBsZW9uaWRzCiAgICBoaWdobGlnaHQ6IGdpdGh1YgogIHBkZl9kb2N1bWVudDoKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6ICc1JwogIGh0bWxfZG9jdW1lbnQ6CiAgICBmaWdfY2FwdGlvbjogeWVzCiAgICBrZWVwX21kOiB5ZXMKICAgIHRvYzogeWVzCiAgICB0b2NfZGVwdGg6IDUKICAgIHRvY19mbG9hdDogeWVzCmVkaXRvcl9vcHRpb25zOiAKICBjaHVua19vdXRwdXRfdHlwZTogaW5saW5lCi0tLQoKCjwhLS0gT3BlbiBhbGwgbGlua3MgaW4gbmV3IHRhYi0tPiAgCjxiYXNlIHRhcmdldD0iX2JsYW5rIi8+ICAKCgo8IS0tIEdvIHRvIHd3dy5hZGR0aGlzLmNvbS9kYXNoYm9hcmQgdG8gY3VzdG9taXplIHlvdXIgdG9vbHMgLS0+IDxzY3JpcHQgdHlwZT0idGV4dC9qYXZhc2NyaXB0IiBzcmM9Ii8vczcuYWRkdGhpcy5jb20vanMvMzAwL2FkZHRoaXNfd2lkZ2V0LmpzI3B1YmlkPXJhLTViYzM2OTAwYTQwNTA5MGIiPiAgCjwvc2NyaXB0PgoKCgpgYGB7ciBnbG9iYWxfb3B0aW9ucywgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gOCwgZmlnLnBhdGggPSAnRmlncy8nLCBlY2hvID0gRkFMU0UsIHdhcm5pbmcgPSBGQUxTRSwgbWVzc2FnZSA9IEZBTFNFLCBlcnJvciA9IEZBTFNFLCBldmFsID0gVFJVRSwgdGlkeSA9IFRSVUUsIGNvbW1lbnQgPSBOQSwgY2FjaGUgPSBUUlVFKQpgYGAKCgoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyB4YXJpbmdhbjo6aW5mX21yKCkKIyBzZXJ2cjo6ZGFlbW9uX3N0b3AoMSkKYGBgCgoKCiMgVGVrcmFybGFuYWJpbGlyIEFuYWxpeiB2ZSBSYXBvcgoKCi0tLQoKCiMjIFJlcGxpY2F0aW9uIENyaXNpcwoKIVtdKGZpZ3VyZXMvcmVwbGljYXRpb25DcmlzaXMucG5nKQoKaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvUmVwbGljYXRpb25fY3Jpc2lzCgoKLS0tCgojIyBSZXBsaWNhdGlvbiBDcmlzaXMgRXhjZWwgVmVyc2lvbgoKWyFbXShmaWd1cmVzL2dlbmVOYW1lc0V4Y2VsLnBuZyldKGh0dHBzOi8vZ2Vub21lYmlvbG9neS5iaW9tZWRjZW50cmFsLmNvbS9hcnRpY2xlcy8xMC4xMTg2L3MxMzA1OS0wMTYtMTA0NC03KQoKCi0tLQoKIyBSU3R1ZGlvIGlsZSBwcm9qZSBvbHXFn3R1cgoKCgohW10oaW1hZ2VzL1JTdHVkaW8tTmV3UHJvamVjdC5naWYpCgoKCi0tLQoKIyBSIE5vdGVib29rICAKCiMjIFIgTm90ZWJvb2sgZMO2a8O8bWFuxLEgb2x1xZ90dXJtYSAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazEuZ2lmKQoKLS0tCgojIyBSIE5vdGVib29rJ3RhbiBodG1sLCBwZGYgdmUgd29yZCBvbHXFn3R1cm1hICAKCgohW10oaW1hZ2VzL1JOb3RlYm9vazIuZ2lmKQoKCi0tLQoKCiMjIFJOb3RlYm9vayB2cyBSTWFya2Rvd24gIAoKCjxpZnJhbWUgd2lkdGg9IjU2MCIgaGVpZ2h0PSIzMTUiIHNyYz0iaHR0cHM6Ly93d3cueW91dHViZS5jb20vZW1iZWQvek56WjFQZlVETmsiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYWNjZWxlcm9tZXRlcjsgYXV0b3BsYXk7IGVuY3J5cHRlZC1tZWRpYTsgZ3lyb3Njb3BlOyBwaWN0dXJlLWluLXBpY3R1cmUiIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4gIAoKCmh0dHBzOi8veW91dHUuYmUvek56WjFQZlVETmsKCgoKCi0tLQoKIyBSIE1hcmtkb3duCgojIyBIZW0ga2VuZGkga29kbGFyxLEgaGVtIGRlIGh0bWwga29kbGFyxLEgeWF6xLFsYWJpbGlyCgpodHRwczovL3JtYXJrZG93bi5yc3R1ZGlvLmNvbQoKPGlmcmFtZSBzcmM9Imh0dHBzOi8vcGxheWVyLnZpbWVvLmNvbS92aWRlby8xNzg0ODU0MTY/Y29sb3I9NDI4YmNhJnRpdGxlPTAmYnlsaW5lPTAmcG9ydHJhaXQ9MCIgd2lkdGg9IjY0MCIgaGVpZ2h0PSI0MDAiIGZyYW1lYm9yZGVyPSIwIiBhbGxvdz0iYXV0b3BsYXk7IGZ1bGxzY3JlZW4iIGFsbG93ZnVsbHNjcmVlbj48L2lmcmFtZT4KPHA+PGEgaHJlZj0iaHR0cHM6Ly92aW1lby5jb20vMTc4NDg1NDE2Ij5XaGF0IGlzIFIgTWFya2Rvd24/PC9hPiBmcm9tIDxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tL3JzdHVkaW9pbmMiPlJTdHVkaW8sIEluYy48L2E+IG9uIDxhIGhyZWY9Imh0dHBzOi8vdmltZW8uY29tIj5WaW1lbzwvYT4uPC9wPgoKLS0tCgojIyBSIE1hcmtkb3duOiBUaGUgRGVmaW5pdGl2ZSBHdWlkZQoKaHR0cHM6Ly9ib29rZG93bi5vcmcveWlodWkvcm1hcmtkb3duLwoKCgoKLS0tCgojIyBSIE1hcmtkb3duIHN5bnRheAoKaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vTWluaGFzS2FtYWwvN2ZkZWJiN2M0MjRkMjMxNDkxNDAKCgo8c2NyaXB0IHNyYz0iaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vTWluaGFzS2FtYWwvN2ZkZWJiN2M0MjRkMjMxNDkxNDAuanMiPjwvc2NyaXB0PgoKCgotLS0KCiMjIFJlbWVkeSBQYWNrYWdlICAKCls8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1RoaW5rUi1vcGVuL3JlbWVkeS9tYXN0ZXIvcmVmZXJlbmNlL2ZpZ3VyZXMvdGhpbmtyLWhleC1yZW1lZHkucG5nIiB3aWR0aD0yNTBweD5dKGh0dHBzOi8vZ2l0aHViLmNvbS9UaGlua1Itb3Blbi9yZW1lZHkpCgoKLS0tCgojIyMgUmVtZWR5ICAKCls8aW1nIHNyYz0iaHR0cHM6Ly9yYXcuZ2l0aHVidXNlcmNvbnRlbnQuY29tL1RoaW5rUi1vcGVuL3JlbWVkeS9tYXN0ZXIvcmVmZXJlbmNlL2ZpZ3VyZXMvcmVtZWR5X2V4YW1wbGUuZ2lmIiB3aWR0aD01MDBweD5dKGh0dHBzOi8vZ2l0aHViLmNvbS9UaGlua1Itb3Blbi9yZW1lZHkpCgoKLS0tCgojIyBSIE1hcmtkb3duIHBha2V0IHZlIMWfYWJsb25sYXLEsSAgCgpodHRwczovL2Jvb2tkb3duLm9yZy95aWh1aS9ybWFya2Rvd24vZG9jdW1lbnQtdGVtcGxhdGVzLmh0bWwKCgohW10oaW1hZ2VzL1JNYXJrZG93blRlbXBsYXRlcy5naWYpCgoKLS0tCgojIyBSZW5kZXIgTWFya2Rvd24gdmlhIGNvZGUKCippbnNpZGUgUioKCmBgYAptYXJrZG93bjo6bWFya2Rvd25Ub0hUTUwoJ21hcmtkb3duX2V4YW1wbGUubWQnLCAKJ21hcmtkb3duX2V4YW1wbGUuaHRtbCcpCmBgYAoKKmNvbW1hbmQgbGluZSoKCmBgYApSIC1lICJtYXJrZG93bjo6bWFya2Rvd25Ub0hUTUwoJ21hcmtkb3duX2V4YW1wbGUubWQnLAonbWFya2Rvd25fZXhhbXBsZS5odG1sJykiCmBgYAoKLS0tCgoKIyMgcGFuZG9jIFJzdHVkaW8gaW50ZWdyYXRpb24KCipjb21tYW5kIGxpbmUqCgpgYGAKZXhwb3J0IFBBVEg9JFBBVEg6L0FwcGxpY2F0aW9ucy9SU3R1ZGlvLmFwcC9Db250ZW50cy9NYWNPUy9wYW5kb2MKYGBgCgoKYGBgClIgLWUgInJtYXJrZG93bjo6cmVuZGVyKCdtYXJrZG93bl9leGFtcGxlLm1kJykiCmBgYAoKCi0tLQoKIyBSTWFya2Rvd24gYGNodW5rYCBpw6dpbmRlIGBSYCBrb2RsYXLEsW7EsSDDp2FsxLHFn3TEsXJtYQoKCmBgYAp7ciwgcmVzdWx0cz0nYXNpcyd9CiBpcmlzICU+JQogIHRpYmJsZTo6YXNfdGliYmxlKCkgJT4lCiAgZGV0YWlsczo6ZGV0YWlscyhzdW1tYXJ5ID0gJ3RpYmJsZScpCmBgYAoKLS0tCgojIE1ldGluIGFyYXPEsW5kYSBgUmAga29kbGFyxLFuxLEgw6dhbMSxxZ90xLFybWEKCgohW10oaW1hZ2VzL2lubGluZVJDb2RlLnBuZykKCgoKLS0tCgojIENodW5rIE9wdGlvbnMKCiMjIEdsb2JhbCBPcHRpb25zCgpgYGAKe3IgZ2xvYmFsX29wdGlvbnMsIGluY2x1ZGU9RkFMU0V9CmtuaXRyOjpvcHRzX2NodW5rJHNldChmaWcud2lkdGggPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIGZpZy5oZWlnaHQgPSA4LAogICAgICAgICAgICAgICAgICAgICAgZmlnLnBhdGggPSAnRmlncy8nLAogICAgICAgICAgICAgICAgICAgICAgZWNobyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgd2FybmluZyA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAogICAgICAgICAgICAgICAgICAgICAgZXJyb3IgPSBGQUxTRSwKICAgICAgICAgICAgICAgICAgICAgIGV2YWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgdGlkeSA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICBjb21tZW50ID0gTkEpCmBgYAoKLS0tCgojIyBPdGhlciBDb2RlIExhbmd1YWdlcwoKClshW10oaHR0cHM6Ly9kMzN3dWJyZmtpMGw2OC5jbG91ZGZyb250Lm5ldC8xNjIzNDdlZjVhZmUyMTlkYTIyZmI3ZDdkOWE1OTg5ZjJjM2U1YTg1LzU5MzE2L2xlc3Nvbi1pbWFnZXMvbGFuZ3VhZ2VzLTEtZGVtb3MucG5nKV0oaHR0cHM6Ly9ybWFya2Rvd24ucnN0dWRpby5jb20vbGVzc29uLTUuaHRtbCkKCgotLS0KCgojIFIgTWFya2Rvd24ga29kIMO2cm5lxJ9pICAKCgpgYGAKe3J9CmRhdGEoImNhbmNlciIpCmNhbmNlcgpmb3JlaWduOjp3cml0ZS5mb3JlaWduKGRmID0gY2FuY2VyLAogICAgICAgICAgICAgICAgICAgICAgICBkYXRhZmlsZSA9ICJkYXRhL2NhbmNlci5zYXYiLAogICAgICAgICAgICAgICAgICAgICAgICBjb2RlZmlsZSA9ICJkYXRhL2NhbmNlci5zcG8iLAogICAgICAgICAgICAgICAgICAgICAgICBwYWNrYWdlID0gIlNQU1MiCiAgICAgICAgICAgICAgICAgICAgICAgICkKYGBgCgoKCgoKLS0tCgojIFIgTWFya2Rvd24gUGFrZXQgw4dhxJ/EsXJtYSDwn5OmICAgIAoKCmBgYAp7cn0Kc3VwcHJlc3NQYWNrYWdlU3RhcnR1cE1lc3NhZ2VzKGxpYnJhcnkoInRpZHl2ZXJzZSIpKQpzdXBwcmVzc1BhY2thZ2VTdGFydHVwTWVzc2FnZXMobGlicmFyeSgic3Vydml2YWwiKSkKYGBgCgoKCiMjIFPEsWsga3VsbGFuZMSxxJ/EsW0gcGFrZXRsZXIg8J+TpiAgCgp7dGlkeXZlcnNlfQp7dGlkeWxvZ30KCntsdWJyaWRhdGV9CntqYW5pdG9yfQoKe3JlYWR4bH0Ke2ZvcmVpZ259Cgp7c3VtbWFyeXRvb2xzfQp7Z2dzdGF0c3Bsb3R9Cnt0YW5ncmFtfQp7ZmluYWxmaXR9Cntwc3ljaG99CntqbXZ9Cgp7c3Vydml2YWx9CntzdXJ2bWluZXJ9Cgp7cmVwb3J0fQp7a2FibGVFeHRyYX0KCi0tLQoKIyBSIE1hcmtkb3duIFZlcmkgWcO8a2xlbWUgU1BTUyAgCgohW10oaW1hZ2VzL2ltcG9ydFNQU1MuZ2lmKQoKCi0tLQoKIyBSIE1hcmtkb3duIFZlcmkgWcO8a2xlbWUgRXhjZWwgIAoKCgohW10oaW1hZ2VzL2ltcG9ydEV4Y2VsLmdpZikKCgotLS0KCiMgVmVyaSBEw7x6ZW5sZW1lCgpgYGAKe3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0UsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9Cm15ZGF0YSA8LSBqYW5pdG9yOjpjbGVhbl9uYW1lcyhteWRhdGEpCmNhdChuYW1lcyhteWRhdGEpLCBzZXAgPSAiLFxuIikKYGBgCgoKYGBgCntyfQpnbGltcHNlKG15ZGF0YSkKYGBgCgoKCmBgYAp7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyMgUmVjb2RpbmcgbXlkYXRhJGNpbnNpeWV0IGludG8gbXlkYXRhJENpbnNpeWV0Cm15ZGF0YSRDaW5zaXlldCA8LSByZWNvZGUobXlkYXRhJGNpbnNpeWV0LAogICAgICAgICAgICAgICAiSyIgPSAiS2FkaW4iLAogICAgICAgICAgICAgICAiRSIgPSAiRXJrZWsiKQpteWRhdGEkQ2luc2l5ZXQgPC0gZmFjdG9yKG15ZGF0YSRDaW5zaXlldCkKYGBgCgoKCgpgYGAKe3IgcmVjb2RlIFROTSBzdGFnZSwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbXlkYXRhJFRzdGFnZSA8LSBzdHJpbmdyOjpzdHJfbWF0Y2gobXlkYXRhJHBhdG9sb2ppa19ldnJlLCBwYXN0ZSgnKC4rKScsICJOIiwgc2VwPScnKSlbLDJdCgpteWRhdGEkTnN0YWdlIDwtIHBhc3RlMCgiTiIsCiAgICBzdHJpbmdyOjpzdHJfbWF0Y2gobXlkYXRhJHBhdG9sb2ppa19ldnJlLCBwYXN0ZSggIk4iLCAnKC4rKScsICJNIiwgc2VwPScnKSlbLDJdCiAgICApCgpteWRhdGEkTXN0YWdlIDwtIHBhc3RlMCgiTSIsIAogICAgc3RyaW5ncjo6c3RyX21hdGNoKG15ZGF0YSRwYXRvbG9qaWtfZXZyZSwgcGFzdGUoIk0iLCAnKC4rKScsIHNlcD0nJykpWywyXQopCmBgYAoKCmBgYAp7ciByZWNvZGUgVE5NMiwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbXlkYXRhIDwtIG15ZGF0YSAlPiUgCiAgICBtdXRhdGUoCiAgICAgICAgVF9zdGFnZSA9IGNhc2Vfd2hlbigKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUMSIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUMSIsCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiVDIiLCB4ID0gLiRUc3RhZ2UpID09IFRSVUUgfiAiVDIiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIlQzIiwgeCA9IC4kVHN0YWdlKSA9PSBUUlVFIH4gIlQzIiwKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJUNCIsIHggPSAuJFRzdGFnZSkgPT0gVFJVRSB+ICJUNCIsCiAgICAgICAgICAgIFRSVUUgfiAiVHgiCiAgICAgICAgKQogICAgKSAlPiUgCm11dGF0ZSgKICAgICAgICBOX3N0YWdlID0gY2FzZV93aGVuKAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIk4wIiwgeCA9IC4kTnN0YWdlKSA9PSBUUlVFIH4gIk4wIiwKICAgICAgICAgICAgZ3JlcGwocGF0dGVybiA9ICJOMSIsIHggPSAuJE5zdGFnZSkgPT0gVFJVRSB+ICJOMSIsCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiTjIiLCB4ID0gLiROc3RhZ2UpID09IFRSVUUgfiAiTjIiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIk4zIiwgeCA9IC4kTnN0YWdlKSA9PSBUUlVFIH4gIk4zIiwKICAgICAgICAgICAgVFJVRSB+ICJOeCIKICAgICAgICApCiAgICApICU+JSAKbXV0YXRlKAogICAgICAgIE1fc3RhZ2UgPSBjYXNlX3doZW4oCiAgICAgICAgICAgIGdyZXBsKHBhdHRlcm4gPSAiTTAiLCB4ID0gLiRNc3RhZ2UpID09IFRSVUUgfiAiTTAiLAogICAgICAgICAgICBncmVwbChwYXR0ZXJuID0gIk0xIiwgeCA9IC4kTXN0YWdlKSA9PSBUUlVFIH4gIk0xIiwKICAgICAgICAgICAgVFJVRSB+ICJNeCIKICAgICAgICApCiAgICApCgoKYGBgCgoKCmBgYAp7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KbXlkYXRhIDwtIG15ZGF0YSAlPiUgCiAgICBtdXRhdGUoClR1bW9yUERMMWdyMSA9IGNhc2Vfd2hlbigKICAgICAgICB0X3BkbDEgPCAxIH4gImt1Y3VrMSIsCiAgICAgICAgdF9wZGwxID49IDEgfiAiYnV5dWtlc2l0MSIKICAgICkKICAgICkgJT4lIAptdXRhdGUoClR1bW9yUERMMWdyNSA9IGNhc2Vfd2hlbigKICAgICAgICB0X3BkbDEgPCA1IH4gImt1Y3VrNSIsCiAgICAgICAgdF9wZGwxID49IDUgfiAiYnV5dWtlc2l0NSIKICAgICkKICAgICkgICAlPiUgCm11dGF0ZSgKaW5mbFBETDFncjEgPSBjYXNlX3doZW4oCiAgICAgICAgaV9wZGwxIDwgMSB+ICJrdWN1azEiLAogICAgICAgIGlfcGRsMSA+PSAxIH4gImJ1eXVrZXNpdDEiCiAgICApCiAgICApICU+JSAKbXV0YXRlKAppbmZsUERMMWdyNSA9IGNhc2Vfd2hlbigKICAgICAgICBpX3BkbDEgPCA1IH4gImt1Y3VrNSIsCiAgICAgICAgaV9wZGwxID49IDUgfiAiYnV5dWtlc2l0NSIKICAgICkKICAgICkKCmBgYAoKCgoKYGBgCntyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpteWRhdGEkc29udGFyaWggPC0gamFuaXRvcjo6ZXhjZWxfbnVtZXJpY190b19kYXRlKGFzLm51bWVyaWMobXlkYXRhJG9sdW1fdGFyaWhpKSkKYGBgCgoKYGBgCntyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpteWRhdGEkT3V0Y29tZSA8LSAiRGVhZCIKbXlkYXRhJE91dGNvbWVbbXlkYXRhJG9sdW1fdGFyaWhpID09ICJ5b2siXSA8LSAiQWxpdmUiCmBgYAoKCgoKCgoKCgotLS0KCiMgUiBNYXJrZG93biBUYW7EsW1sYXnEsWPEsSDEsHN0YXRpc3Rpa2xlciAgCgoKYGBgCntyfQpsaWJyYXJ5KHN1bW1hcnl0b29scykKdmlldyhkZlN1bW1hcnkoY29sb25fcykpCmBgYAoKCi0tLQoKCiMjIFRhYmxlIE9uZSAgCgoKYGBgCntyLCByZXN1bHRzPSdhc2lzJ30KIyBjYXQobmFtZXMobXlkYXRhKSwgc2VwID0gIiArIFxuIikKbGlicmFyeShhcnNlbmFsKQp0YWIxIDwtIHRhYmxlYnkofiBDaW5zaXlldCArIApZYXMgKyAKVHVtb3JZZXJsZXNpbWkKICAgICAgICAgICAgICAgICwKICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEpCnN1bW1hcnkodGFiMSkKYGBgCgoKIyMgVGhlIEdyYW1tYXIgb2YgVGFibGVzCgoKW3RhbmdyYW06IFRoZSBHcmFtbWFyIG9mIFRhYmxlc10oaHR0cHM6Ly9jcmFuLnItcHJvamVjdC5vcmcvd2ViL3BhY2thZ2VzL3RhbmdyYW0vKQoKW0EgZ3JhbW1hciBvZiB0YWJsZXNdKGh0dHBzOi8vZ2l0aHViLmNvbS9sZWVwZXIvdHR0YWJsZSkKCltHcmFtbWFyIG9mIFRhYmxlcz9dKGh0dHBzOi8vZ2lzdC5naXRodWIuY29tL2xlZXBlci9mOWNmYmU2YmQxODU3NjM3NjJlMTI2YTRkOGQ3YzI4NikKCltFYXNpbHkgZ2VuZXJhdGUgaW5mb3JtYXRpb24tcmljaCwgcHVibGljYXRpb24tcXVhbGl0eSB0YWJsZXMgZnJvbSBSXShodHRwczovL2d0LnJzdHVkaW8uY29tKQoKCiMjIEthdGVnb3JpayBWZXJpbGVyCgoKYGBgCntyICIsIG5hbWVzKG15ZGF0YUNhdGVnb3JpY2FsKVtpXSwgIn0KbXlkYXRhQ2F0ZWdvcmljYWwgJT4lIAogIGphbml0b3I6OnRhYnlsKCIsIG5hbWVzKG15ZGF0YUNhdGVnb3JpY2FsKVtpXSwgIikgJT4lCiAgYWRvcm5fcGN0X2Zvcm1hdHRpbmcocm91bmRpbmcgPSAnaGFsZiB1cCcsIGRpZ2l0cyA9IDEpICU+JQogIGtuaXRyOjprYWJsZSgpCmBgYAoKCgpgYGAKe3IgY3Jvc3N0YWJsZSIsIGRlcGVuZGVudF92YXJpYWJsZSwgIn0KbXlkYXRhICU+JQogICAgc3VtbWFyeV9mYWN0b3JsaXN0KGRlcGVuZGVudCA9ICciLCBkZXBlbmRlbnRfdmFyaWFibGUsICInLCAKICAgICAgICAgICAgICAgICAgICAgICBleHBsYW5hdG9yeSA9IGV4cGxhbmF0b3J5LAogICAgICAgICAgICAgICAgICAgICAgIHRvdGFsX2NvbCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgcCA9IFRSVUUsCiAgICAgICAgICAgICAgICAgICAgICAgYWRkX2RlcGVuZGVudF9sYWJlbCA9IFRSVUUpIC0+IHRhYmxlCgprbml0cjo6a2FibGUodGFibGUsIHJvdy5uYW1lcyA9IEZBTFNFLCBhbGlnbiA9IGMoJ2wnLCAnbCcsICdyJywgJ3InLCAncicpKQpgYGAKCi0tLQoKCiMjIEthdGVnb3JpayBWZXJpbGVyIGnDp2luIEdyYWZpa2xlciAgCgpgYGAKe3IgZ2dzdGF0cGxvdCAiLCBkZXBlbmRlbnRfdmFyaWFibGUgLCAiIHZzICIsIG15ZGF0YUNhdGVnb3JpY2FsX3ZhcmlhYmxlLCAiLCBsYXlvdXQ9J2wtcGFnZSd9Cm15ZGF0YSAlPiUgCiAgICBnZ3N0YXRzcGxvdDo6Z2diYXJzdGF0cyhkYXRhID0gLiwgbWFpbiA9ICIsIG15ZGF0YUNhdGVnb3JpY2FsX3ZhcmlhYmxlLCAiLCBjb25kaXRpb24gPSAiLCBkZXBlbmRlbnRfdmFyaWFibGUsICIpCmBgYAoKCi0tLQoKCiMjIENvbnRpbmlvdXMgVmFyaWFibGVzCgoKCmBgYAp7ciAiLCBuYW1lcyhteWRhdGFDb250aW5pb3VzKVtpXSwgIn0KbXlkYXRhQ29udGluaW91cyAlPiUgCmptdjo6ZGVzY3JpcHRpdmVzKAogICAgZGF0YSA9IC4sCiAgICB2YXJzID0gIiwgbmFtZXMobXlkYXRhQ29udGluaW91cylbaV0sICIsCiAgICBoaXN0ID0gVFJVRSwKICAgIGRlbnMgPSBUUlVFLAogICAgYm94ID0gVFJVRSwKICAgIHZpb2xpbiA9IFRSVUUsCiAgICBkb3QgPSBUUlVFLAogICAgbW9kZSA9IFRSVUUsCiAgICBzZCA9IFRSVUUsCiAgICB2YXJpYW5jZSA9IFRSVUUsCiAgICBza2V3ID0gVFJVRSwKICAgIGt1cnQgPSBUUlVFLAogICAgcXVhcnQgPSBUUlVFKQpgYGAKCgoKCi0tLQoKIyBSIE1hcmtkb3duIFJlY29kZSAgCgpyZWNvZGUKCgoKLS0tCgojIFIgTWFya2Rvd24gw7ZybmXEn2kgw4dhcHJheiBUYWJsb2xhciAgCgpsaWJyYXJ5KGZpbmFsZml0KQoKCmBgYAp7ciBjcm9zc3RhYmxlIiwgZGVwZW5kZW50X3ZhcmlhYmxlLCAiLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpteWRhdGEgJT4lCiAgICBzdW1tYXJ5X2ZhY3Rvcmxpc3QoZGVwZW5kZW50ID0gJyIsIGRlcGVuZGVudF92YXJpYWJsZSwgIicsIAogICAgICAgICAgICAgICAgICAgICAgIGV4cGxhbmF0b3J5ID0gZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgICAgICAgY29sdW1uID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgICB0b3RhbF9jb2wgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIHAgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIGFkZF9kZXBlbmRlbnRfbGFiZWwgPSBUUlVFLAogICAgICAgICAgICAgICAgICAgICAgIG5hX2luY2x1ZGU9RkFMU0UKICAgICAgICAgICAgICAgICAgICAgICAjIGNhdFRlc3QgPSBjYXRUZXN0ZmlzaGVyCiAgICAgICAgICAgICAgICAgICAgICAgKSAtPiB0YWJsZQoKa25pdHI6OmthYmxlKHRhYmxlLCByb3cubmFtZXMgPSBGQUxTRSwgYWxpZ24gPSBjKCdsJywgJ2wnLCAncicsICdyJywgJ3InKSkKYGBgCgoKLS0tCgojIFIgTWFya2Rvd24gw7ZybmXEn2kgU2HEn2thbMSxbSAgCgotIERyYXdpbmcgU3Vydml2YWwgQ3VydmVzIFVzaW5nIGdncGxvdDIgIApodHRwczovL3Jwa2dzLmRhdGFub3ZpYS5jb20vc3Vydm1pbmVyL3JlZmVyZW5jZS9nZ3N1cnZwbG90Lmh0bWwKCiMjIEthcGxhbi1NZWllcgoKYGBgCntyIEthcGxhbi1NZWllcn0KbXlkYXRhICU+JQogIGZpbmFsZml0OjpzdXJ2X3Bsb3QoZGVwZW5kZW50LAogICAgICAgICAgICAgICAgICAgICAgZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgICAgICB4bGFiPSdUaW1lIChtb250aHMpJywKICAgICAgICAgICAgICAgICAgICAgIHB2YWw9VFJVRSwKICAgICAgICAgICAgICAgICAgICAgIGxlZ2VuZCA9ICdub25lJywKICAgICAgICAgICAgICAgICAgICAgIGJyZWFrLnRpbWUuYnkgPSAxMiwKICAgICAgICAgICAgICAgICAgICAgIHhsaW0gPSBjKDAsNjApLAogICAgICAgICAgICAgICAgICAgICAgbGVnZW5kLmxhYnMgPSBjKCdhJywnYicpCikKYGBgCgojIyBTYcSfa2FsxLFtIFRhYmxvbGFyxLEKCmBgYAp7cn0Ka21fZml0IDwtIHN1cnZmaXQoZGVwZW5kZW50IH4gZXhwbGFuYXRvcnksCiAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEpCmttX2ZpdApgYGAKCgpgYGAKe3IsIGV2YWw9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CmxpYnJhcnkoc3Vydml2YWwpCmttIDwtIHdpdGgobXlkYXRhLCBTdXJ2KE92ZXJhbGxUaW1lLCBPdXRjb21lMikpCiMgaGVhZChrbSw4MCkKIyBwbG90KGttKQpgYGAKCgoKCgpgYGAKe3IgMS0zLTUteXJ9CnN1bW1hcnkoa21fZml0LCB0aW1lcyA9IGMoMTIsMzYsNjApKQpgYGAKCgoKCgojIFBhaXJ3aXNlIGNvbXBhcmlzb24KCmBgYAp7ciBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpzdXJ2bWluZXI6OnBhaXJ3aXNlX3N1cnZkaWZmKGZvcm11bGEgPSBTdXJ2KHRpbWUsIE91dGNvbWUpIH4gU2hlbGxBbnRlcmlvck9ubHksIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEgPSBteWRhdGEsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIikKYGBgCgoKCgoKIyBNdWx0aXZhcmlhdGUgQW5hbHlzaXMgU3Vydml2YWwKCgpgYGAKe3IgTXVsdGl2YXJpYXRlIEFuYWx5c2lzLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpsaWJyYXJ5KGZpbmFsZml0KQpsaWJyYXJ5KHN1cnZpdmFsKQpleHBsYW5hdG9yeU11bHRpdmFyaWF0ZSA8LSBleHBsYW5hdG9yeUtNCmRlcGVuZGVudE11bHRpdmFyaWF0ZSA8LSBkZXBlbmRlbnRLTQoKbXlkYXRhICU+JQogIGZpbmFsZml0KGRlcGVuZGVudE11bHRpdmFyaWF0ZSwgZXhwbGFuYXRvcnlNdWx0aXZhcmlhdGUpIC0+IHRNdWx0aXZhcmlhdGUKCmtuaXRyOjprYWJsZSh0TXVsdGl2YXJpYXRlLCByb3cubmFtZXM9RkFMU0UsIGFsaWduPWMoImwiLCAibCIsICJyIiwgInIiLCAiciIsICJyIikpCmBgYAoKCgoKYGBgCntyIGRlZmluZSBzdXJ2aXZhbCB0aW1lLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpteWRhdGEkaW50IDwtIGx1YnJpZGF0ZTo6aW50ZXJ2YWwoCiAgbHVicmlkYXRlOjp5bWQobXlkYXRhJENlcnJhaGlUYXJpaCksCiAgbHVicmlkYXRlOjp5bWQobXlkYXRhJFNvblRhcmloKQogICkKbXlkYXRhJE92ZXJhbGxUaW1lIDwtIGx1YnJpZGF0ZTo6dGltZV9sZW5ndGgobXlkYXRhJGludCwgIm1vbnRoIikKbXlkYXRhJE92ZXJhbGxUaW1lIDwtIHJvdW5kKG15ZGF0YSRPdmVyYWxsVGltZSwgZGlnaXRzID0gMSkKYGBgCgoKYGBgCntyLCBldmFsPUZBTFNFLCBpbmNsdWRlPUZBTFNFfQpteWRhdGEkT3ZlcmFsbFRpbWUgPC0gbXlkYXRhJGdlbmVsX3NhZ2thbGltCmBgYAoKCmBgYAp7ciwgZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyMgUmVjb2RpbmcgbXlkYXRhJE91dGNvbWUgaW50byBteWRhdGEkT3V0Y29tZTIKbXlkYXRhJE91dGNvbWUyIDwtIHJlY29kZShteWRhdGEkT3V0Y29tZSwKICAgICAgICAgICAgICAgIkFsaXZlIiA9ICIwIiwKICAgICAgICAgICAgICAgIkRlYWQiID0gIjEiKQpteWRhdGEkT3V0Y29tZTIgPC0gYXMubnVtZXJpYyhteWRhdGEkT3V0Y29tZTIpCgpgYGAKCgoKCgoKCgoKCgotLS0KCgojIGphbW92aSB2ZSBSIGVudGVncmFzeW9udQoKW1JqIEVkaXRvciDigJMgQW5hbHlzZSB5b3VyIGRhdGEgd2l0aCBSIGluIGphbW92aV0oaHR0cHM6Ly9ibG9nLmphbW92aS5vcmcvMjAxOC8wNy8zMC9yai5odG1sKQoKCgoKCiMge2ptdn0gcGFrZXQga29kbGFyxLEKCltqYW1vdmkgc3ludGF4IG1vZGVdKGh0dHBzOi8vd3d3LmphbW92aS5vcmcvdXNlci1tYW51YWwuaHRtbCNzeW50YXgtbW9kZSkKCgoKCi0tLQoKIyBHw7xuY2VsbGVtZWxlciBvbHVuY2Ega29kbGFyIMOnYWzEscWfYWNhayBtxLE/CgoKLS0tCgoKIyMgUGFrZXQgS8O8dMO8cGhhbmVsZXJpCgotIHBhY2tyYXQgLyByZW52CgpodHRwczovL2Vudmlyb25tZW50cy5yc3R1ZGlvLmNvbQoKCi0tLQoKCiMjIERvY2tlcgoKCi0gZG9ja2VyCgotLS0KCiMjIyBUaGUgUm9ja2VyIFByb2plY3QKCkRvY2tlciBDb250YWluZXJzIGZvciB0aGUgUiBFbnZpcm9ubWVudAoKYGBgCmRvY2tlciBydW4gLS1ybSAtdGkgcm9ja2VyL3ItYmFzZQpgYGAKCk9yIGdldCBzdGFydGVkIHdpdGggYW4gUlN0dWRpb8KuIGluc3RhbmNlOgoKYGBgCmRvY2tlciBydW4gLWUgUEFTU1dPUkQ9eW91cnBhc3N3b3JkIC0tcm0gLXAgODc4Nzo4Nzg3IHJvY2tlci9yc3R1ZGlvCmBgYAoKYW5kIHBvaW50IHlvdXIgYnJvd3NlciB0byBbbG9jYWxob3N0Ojg3ODddKGxvY2FsaG9zdDo4Nzg3KQpMb2cgaW4gd2l0aCB1c2VyL3Bhc3N3b3JkIHJzdHVkaW8veW91cnBhc3N3b3JkIAoKCi0tLQoKWyFbXShpbWFnZXMvVGhlUm9ja2VyUHJvamVjdC5wbmcpXShodHRwczovL3d3dy5yb2NrZXItcHJvamVjdC5vcmcpCgpbTWFuYWdpbmcgY29udGFpbmVyc10oaHR0cHM6Ly93d3cucm9ja2VyLXByb2plY3Qub3JnL3VzZS9tYW5hZ2luZ19jb250YWluZXJzLykKCgoKCi0tLQoKIyMgWWVuaSBSIHPDvHLDvG1sZXJpIAoKLSBSU3dpdGNoCgpodHRwczovL3J1ZC5pcy9yc3dpdGNoLwoKLSBVc2luZyBSU3dpdGNoCgpodHRwczovL3J1ZC5pcy9yc3dpdGNoL2d1aWRlLwoKCiFbOiBzY2FsZSAzMCVdKGh0dHBzOi8vcnVkLmlzL3Jzd2l0Y2gvZ3VpZGUvbWVudS1pbmZvLnBuZykKCgoKLS0tCgojIFllZGVrbGVtZXlpIG5hc8SxbCB5YXBhY2HEn8SxegoKCiMjIFByb2pleWkgZMO8emfDvG4gb3JnYW5pemUgZWRpbgoKLSBwZGYKLSBSCi0gaW1hZ2VzCi0gYmliCgpgYGAKe3IgbG9hZCBsaWJyYXJ5LCBpbmNsdWRlPUZBTFNFfQpzb3VyY2UoZmlsZSA9IGhlcmU6OmhlcmUoIlIiLCAibG9hZExpYnJhcnkuUiIpKQpgYGAKCgoKLS0tCgoKIyMgU2F2ZSBGaW5hbCBEYXRhCgoKYGBgCntyfQpzYXZlZCBkYXRhIGFmdGVyIGFuYWx5c2lzIHRvIGBteWRhdGEueGxzeGAuCgpzYXZlLmltYWdlKGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YV93b3JrX3NwYWNlLlJEYXRhIikpCgpyZWFkcjo6d3JpdGVfcmRzKHggPSBteWRhdGEsIHBhdGggPSBoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YV9hZnRlcmFuYWx5c2lzLnJkcyIpKQoKc2F2ZVJEUyhvYmplY3QgPSBteWRhdGEsIGZpbGUgPSBoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS5yZHMiKSkKCndyaXRleGw6OndyaXRlX3hsc3gobXlkYXRhLCBoZXJlOjpoZXJlKCJkYXRhIiwgIm15ZGF0YS54bHN4IikpCgpwYXN0ZTAocm93bmFtZXMoZmlsZS5pbmZvKGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhLnhsc3giKSkpLCAiIDogIiwgZmlsZS5pbmZvKGhlcmU6OmhlcmUoImRhdGEiLCAibXlkYXRhLnhsc3giKSkkY3RpbWUpCgpgYGAKCgoKCiMjIEdpdEh1YiAgCgpgYGAKe3IgZ2l0aHViIHB1c2h9CkNvbW1pdE1lc3NhZ2UgPC0gcGFzdGUoInVwZGF0ZWQgb24gIiwgU3lzLnRpbWUoKSwgc2VwID0gIiIpCndkIDwtIGdldHdkKCkKZ2l0Q29tbWFuZCA8LSBwYXN0ZSgiY2QgIiwgCiAgICAgICAgICAgICAgICAgICAgd2QsCiAgICAgICAgICAgICAgICAgICAgIiBcbiBnaXQgYWRkIC4gXG4gZ2l0IGNvbW1pdCAtLW1lc3NhZ2UgJyIsCiAgICAgICAgICAgICAgICAgICAgQ29tbWl0TWVzc2FnZSwKICAgICAgICAgICAgICAgICAgICAiJyBcbiBnaXQgcHVzaCBvcmlnaW4gbWFzdGVyIFxuIiwKICAgICAgICAgICAgICAgICAgICBzZXAgPSAiIgogICAgICAgICAgICAgICAgICAgICkKc3lzdGVtKGNvbW1hbmQgPSBnaXRDb21tYW5kLAogICAgICAgaW50ZXJuID0gVFJVRQopCmBgYAoKLS0tCgojIyBHaXRIdWIgWWVkZWtsZW1lCgpgYGB7ciBnaXRodWIgcHVzaCwgZWNobz1UUlVFfQpDb21taXRNZXNzYWdlIDwtIHBhc3RlKCJ1cGRhdGVkIG9uICIsIFN5cy50aW1lKCksIHNlcCA9ICIiKQp3ZCA8LSBnZXR3ZCgpCmdpdENvbW1hbmQgPC0gcGFzdGUoImNkICIsIAogICAgICAgICAgICAgICAgICAgIHdkLAogICAgICAgICAgICAgICAgICAgICIgXG4gZ2l0IGFkZCAuIFxuIGdpdCBjb21taXQgLS1tZXNzYWdlICciLAogICAgICAgICAgICAgICAgICAgIENvbW1pdE1lc3NhZ2UsCiAgICAgICAgICAgICAgICAgICAgIicgXG4gZ2l0IHB1c2ggb3JpZ2luIG1hc3RlciBcbiIsCiAgICAgICAgICAgICAgICAgICAgc2VwID0gIiIKICAgICAgICAgICAgICAgICAgICApCgpzeXN0ZW0oY29tbWFuZCA9IGdpdENvbW1hbmQsCiAgICAgICBpbnRlcm4gPSBUUlVFCikKYGBgCgoKCgotLS0KCgojIEhlciBkw7Zrw7xtYW7EsW4gc29udW5hIGt1bGxhbmTEscSfxLFuxLF6IGvDvHTDvHBoYW5lbGVyIGnDp2luIGF0xLFmIHlhemTEsXJhYmlsaXJzaW5pegoKCmBgYAp7ciBsaWJyYXJ5IGNpdGF0aW9uLCBlY2hvPVRSVUV9CmNpdGF0aW9uKCkKCmBgYAoKCgoKLS0tCgoKIyMgTGlicmFyaWVzIFVzZWQgIAoKYGBge3IgbGlicmFyeSBjaXRhdGlvbiwgZWNobz1UUlVFfQpjaXRhdGlvbigpCmBgYAoKCgotLS0KCgojIyBCdSBvdHVydW1hIHNwZXNpZmlrIGt1bGxhbsSxbGFuIHBha2V0bGVyICAKCgoKYGBge3IgbGlicmFyeSBjaXRhdGlvbiBhcyByZXBvcnQsIGVjaG89VFJVRSwgcmVzdWx0cz0nYXNpcyd9CnJlcG9ydDo6Y2l0ZV9wYWNrYWdlcyhzZXNzaW9uID0gc2Vzc2lvbkluZm8oKSkKYGBgCgoKLS0tCgojIyBUZWsgdGVrIHBha2V0IGF0xLFmbGFyxLEKCgpgYGAKe3IgbGlicmFyeSBjaXRhdGlvbnN9CmNpdGF0aW9uKCJ0aWR5dmVyc2UiKQoKYGBgCgoKYGBgCntyfQpjaXRhdGlvbigicmVhZHhsIikKY2l0YXRpb24oImphbml0b3IiKQpjaXRhdGlvbigicmVwb3J0IikKY2l0YXRpb24oImZpbmFsZml0IikKY2l0YXRpb24oImdnc3RhdHBsb3QiKQpgYGAKCgotLS0KCiMjIEphbW92aSB2ZSBSIGnDp2luIGF0xLFmIMO2cm5lxJ9pCgpUaGUgamFtb3ZpIHByb2plY3QgKDIwMTkpLiBqYW1vdmkuIChWZXJzaW9uIDAuOSkgW0NvbXB1dGVyIFNvZnR3YXJlXS4gUmV0cmlldmVkIGZyb20gaHR0cHM6Ly93d3cuamFtb3ZpLm9yZy4KUiBDb3JlIFRlYW0gKDIwMTgpLiBSOiBBIExhbmd1YWdlIGFuZCBlbnZpb25tZW50IGZvciBzdGF0aXN0aWNhbCBjb21wdXRpbmcuIFtDb21wdXRlciBzb2Z0d2FyZV0uIFJldHJpZXZlZCBmcm9tIGh0dHBzOi8vY3Jhbi5yLXByb2plY3Qub3JnLy4KRm94LCBKLiwgJiBXZWlzYmVyZywgUy4gKDIwMTgpLiBjYXI6IENvbXBhbmlvbiB0byBBcHBsaWVkIFJlZ3Jlc3Npb24uIFtSIHBhY2thZ2VdLiBSZXRyaWV2ZWQgZnJvbSBodHRwczovL2NyYW4uci1wcm9qZWN0Lm9yZy9wYWNrYWdlPWNhci4KCgoKLS0tCgoKCiMgSGVyIGTDtmvDvG1hbsSxbiBzb251bmEgb3R1cnVtIGRldGF5bGFyxLFuxLF6xLEgeWF6ZMSxcmFiaWxpcnNpbml6ICAKCgpgYGAKe3Igc2Vzc2lvbiBpbmZvLCBlY2hvPVRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgoKCgotLS0KCgoKIyMgU2Vzc2lvbiBJbmZvCgoKYGBge3Igc2Vzc2lvbiBpbmZvLCBlY2hvPVRSVUV9CnNlc3Npb25JbmZvKCkKYGBgCgoKLS0tCgojIFNvbnJha2kgS29udWxhcgoKLSBSU3R1ZGlvIGlsZSBHaXRIdWIga3VsbGFuxLFtxLEKLSAuLi4KCgotLS0KCiMgU3VudW0gTGlua2xlcmkKCmh0dHBzOi8vc2JhbGNpLmdpdGh1Yi5pby9NeVJDb2Rlc0ZvckRhdGFBbmFseXNpcy9SLU1hcmtkb3duLm5iLmh0bWwKaHR0cHM6Ly9zYmFsY2kuZ2l0aHViLmlvL015UkNvZGVzRm9yRGF0YUFuYWx5c2lzL1ItTWFya2Rvd24uaHRtbAoKaHR0cHM6Ly9mb3Jtcy5nbGUvVXFHSkJpQWpCOHVMUFJvbjgKCi0tLQoKCiMgR2VyaSBCaWxkaXJpbQoKLSBHZXJpIGJpbGRpcmltIGnDp2luIHTEsWtsYXnEsW7EsXo6IF9bR2VyaSBiaWxkaXJpbSBmb3JtdV0oaHR0cHM6Ly9nb28uZ2wvZm9ybXMvWWpHWjVESGd0UGxSMVJuQjMpXwoKCi0tLQoKCjxzY3JpcHQgaWQ9ImRzcS1jb3VudC1zY3IiIHNyYz0iLy9odHRwcy1zYmFsY2ktZ2l0aHViLWlvLmRpc3F1cy5jb20vY291bnQuanMiIGFzeW5jPjwvc2NyaXB0PgoKPGRpdiBpZD0iZGlzcXVzX3RocmVhZCI+PC9kaXY+CjxzY3JpcHQ+CgovKioKKiAgUkVDT01NRU5ERUQgQ09ORklHVVJBVElPTiBWQVJJQUJMRVM6IEVESVQgQU5EIFVOQ09NTUVOVCBUSEUgU0VDVElPTiBCRUxPVyBUTyBJTlNFUlQgRFlOQU1JQyBWQUxVRVMgRlJPTSBZT1VSIFBMQVRGT1JNIE9SIENNUy4KKiAgTEVBUk4gV0hZIERFRklOSU5HIFRIRVNFIFZBUklBQkxFUyBJUyBJTVBPUlRBTlQ6IGh0dHBzOi8vZGlzcXVzLmNvbS9hZG1pbi91bml2ZXJzYWxjb2RlLyNjb25maWd1cmF0aW9uLXZhcmlhYmxlcyovCi8qCnZhciBkaXNxdXNfY29uZmlnID0gZnVuY3Rpb24gKCkgewp0aGlzLnBhZ2UudXJsID0gUEFHRV9VUkw7ICAvLyBSZXBsYWNlIFBBR0VfVVJMIHdpdGggeW91ciBwYWdlJ3MgY2Fub25pY2FsIFVSTCB2YXJpYWJsZQp0aGlzLnBhZ2UuaWRlbnRpZmllciA9IFBBR0VfSURFTlRJRklFUjsgLy8gUmVwbGFjZSBQQUdFX0lERU5USUZJRVIgd2l0aCB5b3VyIHBhZ2UncyB1bmlxdWUgaWRlbnRpZmllciB2YXJpYWJsZQp9OwoqLwooZnVuY3Rpb24oKSB7IC8vIERPTidUIEVESVQgQkVMT1cgVEhJUyBMSU5FCnZhciBkID0gZG9jdW1lbnQsIHMgPSBkLmNyZWF0ZUVsZW1lbnQoJ3NjcmlwdCcpOwpzLnNyYyA9ICdodHRwczovL2h0dHBzLXNiYWxjaS1naXRodWItaW8uZGlzcXVzLmNvbS9lbWJlZC5qcyc7CnMuc2V0QXR0cmlidXRlKCdkYXRhLXRpbWVzdGFtcCcsICtuZXcgRGF0ZSgpKTsKKGQuaGVhZCB8fCBkLmJvZHkpLmFwcGVuZENoaWxkKHMpOwp9KSgpOwo8L3NjcmlwdD4KPG5vc2NyaXB0PlBsZWFzZSBlbmFibGUgSmF2YVNjcmlwdCB0byB2aWV3IHRoZSA8YSBocmVmPSJodHRwczovL2Rpc3F1cy5jb20vP3JlZl9ub3NjcmlwdCI+Y29tbWVudHMgcG93ZXJlZCBieSBEaXNxdXMuPC9hPjwvbm9zY3JpcHQ+CgoKLS0tCgojIMSwbGV0acWfaW0gIAoKQ29tcGxldGVkIG9uIGByIFN5cy5EYXRlKClgLiAgCgpTZXJkYXIgQmFsY2ksIE1ELCBQYXRob2xvZ2lzdCAgCmRyc2VyZGFyYmFsY2lAZ21haWwuY29tICAKCmh0dHBzOi8vcnB1YnMuY29tL3NiYWxjaS9DViAgIApodHRwczovL3NiYWxjaS5naXRodWIuaW8vICAKaHR0cHM6Ly9naXRodWIuY29tL3NiYWxjaSAgCmh0dHBzOi8vdHdpdHRlci5jb20vc2VyZGFyYmFsY2kKCgotLS0KCgoKCgotLS0KCgojIE90aGVyIExpbmtzCgoKaHR0cHM6Ly9hbmRyZXdidHJhbi5naXRodWIuaW8vTklDQVIvMjAxOC93b3JrZmxvdy9kb2NzLzAyLXJtYXJrZG93bi5odG1sCgotIFRyb3VibGVzaG9vdGluZyBpbiBSIE1hcmtkb3duCgpodHRwczovL3NtaXRoY29sbGVnZS1zZHMuZ2l0aHViLmlvL3Nkcy1wdWJsaWMvcm1hcmtkb3duX3Byb2JsZW1zLmh0bWwKCgpodHRwOi8va2Jyb21hbi5vcmcva25pdHJfa251dHNoZWxsL3BhZ2VzL1JtYXJrZG93bi5odG1sCgpodHRwczovL2ticm9tYW4ub3JnL2tuaXRyX2tudXRzaGVsbC9wYWdlcy9vdmVydmlldy5odG1sCgpodHRwczovL2ticm9tYW4ub3JnL2tuaXRyX2tudXRzaGVsbC9wYWdlcy9SbWFya2Rvd24uaHRtbAoKaHR0cHM6Ly9rYnJvbWFuLm9yZy9rbml0cl9rbnV0c2hlbGwvcGFnZXMvbWFya2Rvd24uaHRtbAoKCmh0dHBzOi8vb25wNC5jb20vCgoKCmBgYApjc3Yge2hlYWRlcnM6IHRydWUsIHRpdGxlOiAiKipEcmF3aW5nIFRhYmxlcyBJbiBNYXJrZG93bioqIn0KTmFtZSwgU3VybmFtZSwgS25vd24gQXMsIEFnZQpNYXJjZWxvLCBEYXZpZCwgY29sZHplcmEsIDIyCk9sZWtzYW5kciwgS29zdHlsaWV2LCBzMW1wbGUsIDE5Ck5pa29sYSwgS292YcSNLCBOaUtvLCAyMApSaWNoYXJkLCBQYXBpbGxvbiwgc2hveCwgMjUKTmljb2xhaSwgUmVlZHR6LCBkZXYxY2UsIDIxCmBgYAoKYGBgCntwZ259CltFdmVudCAiQmxlZC1aYWdyZWItQmVsZ3JhZGUgQ2FuZGlkYXRlcyJdCltTaXRlICJCbGVkLCBaYWdyZWIgJiBCZWxncmFkZSBZVUciXQpbRGF0ZSAiMTk1OS4xMC4xMSJdCltSb3VuZCAiMjAiXQpbUmVzdWx0ICIxLTAiXQpbV2hpdGUgIk1pa2hhaWwgVGFsIl0KW0JsYWNrICJSb2JlcnQgSmFtZXMgRmlzY2hlciJdCgoxLiBkNCBOZjYgMi4gYzQgZzYgMy4gTmMzIEJnNyA0LiBlNCBkNiA1LgpCZTIgTy1PIDYuIE5mMyBlNSA3LiBkNSBOYmQ3IDguIEJnNSBoNiA5LgpCaDQgYTYgMTAuIE8tTyBRZTggMTEuIE5kMiBOaDcgMTIuIGI0IEJmNgoxMy4gQnhmNiBOaHhmNiAxNC4gTmIzIFFlNyAxNS4gUWQyIEtoNyAxNi4KUWUzIE5nOCAxNy4gYzUgZjUgMTguIGV4ZjUgZ3hmNSAxOS4gZjQgZXhmNAoyMC4gUXhmNCBkeGM1IDIxLiBCZDMgY3hiNCAyMi4gUmFlMSBRZjYgMjMuClJlNiBReGMzIDI0LiBCeGY1KyBSeGY1IDI1LiBReGY1KyBLaDggMjYuClJmMyBRYjIgMjcuIFJlOCBOZjYgMjguIFF4ZjYrIFF4ZjYgMjkuIFJ4ZjYKS2c3IDMwLiBSZmY4IE5lNyAzMS4gTmE1IGg1IDMyLiBoNCBSYjggMzMuCk5jNCBiNSAzNC4gTmU1IDEtMApgYGAKCgotIEtlZXBpbmcgQ3JlZGVudGlhbHMgU2VjcmV0IHdpdGggS2V5cmluZ3MgaW4gUgoKaHR0cHM6Ly9yYXM0NC5naXRodWIuaW8vYmxvZy8yMDE5LzAxLzE5L2tlZXBpbmctY3JlZGVudGlhbHMtc2VjcmV0LXdpdGgta2V5cmluZ3MtaW4tci5odG1sCgotIEhvdyB0byBidWlsZCBhIHdlYnNpdGUgd2l0aCBCbG9nZG93biBpbiBSCgpodHRwOi8vd3d3LnN0b3J5YmVuY2gub3JnL2hvdy10by1idWlsZC1hLXdlYnNpdGUtd2l0aC1ibG9nZG93bi1pbi1yLwo=